﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevComponents.DotNetBar.Charts;
using DevComponents.DotNetBar.Charts.Style;

namespace SampleDataTools
{
    public partial class ChartControl2x2 : UserControl
    {
        internal ChartGroupConfig Config { get; set; }

        private ChartXy[] chartXyControls;
        private int maxPointCount;
        private List<ControlDataUpdater<Tuple<int, ChartSeries>>>[] chartXyUpdateCollections;

        public ChartControl2x2()
        {
            InitializeComponent();
            maxPointCount = 1000;
            chartXyUpdateCollections = new List<ControlDataUpdater<Tuple<int, ChartSeries>>>[]{
            new List<ControlDataUpdater<Tuple<int, ChartSeries>>>(),
            new List<ControlDataUpdater<Tuple<int, ChartSeries>>>()
            };
            SetupChart();
        }

        public void Update(BuffData[] datas)
        {
            if (datas == null)
            {
                return;
            }
            foreach (var collection in chartXyUpdateCollections)
            {
                foreach (var item in collection)
                {
                    int index = item.Parameter.Item1;
                    if (index < datas.Length)
                    {
                        var data = datas[index];
                        item.Update(data);
                    }
                }
            }
        }

        public void ClearSeries()
        {
            foreach (var item in chartXyControls)
            {
                foreach (var series in item.ChartSeries)
                {
                    series.SeriesPoints.Clear();
                }
            }        
        }
        #region Chart setting

        private void SettingMenuClicked(object sender, EventArgs e)
        {
            dynamic menu = sender;
            int index = menu.Tag;
            var cloneConfig = Config.Clone();
            var targetConfig = cloneConfig.Items[index];

            PropertyForm form = new PropertyForm
            {
                PropertyValue = targetConfig
            };
            if (form.ShowDialog(this) == DialogResult.OK)
            {
                Config.Items[index] = form.PropertyValue as ChartConfig;

                SetupSeries(index);
            }
        }

        /// <summary>
        /// Initializes the control chart.
        /// </summary>
        private void SetupChart()
        {
            ChartControl[] chartControls = new ChartControl[4];
            chartXyControls = new ChartXy[4];
            for (int chartControlIndex = 0; chartControlIndex < chartControls.Length; chartControlIndex++)
            {
                ChartControl chart = new ChartControl();
                chartControls[chartControlIndex] = chart;
                chart.Name = "RealTimePlot";
                chart.Dock = DockStyle.Fill;
                SetupScrollBarStyles(chart);
                chartXyControls[chartControlIndex] = AddChart(chart);

                chart.ContextMenuStrip = new ContextMenuStrip();

                chart.ContextMenuStrip.Items.Add("图表设置", null, SettingMenuClicked).Tag = chartControlIndex;
            }

            // ADD to table
            tableLayoutPanel1.Controls.AddRange(chartControls);
            tableLayoutPanel1.SetColumn(chartControls[0], 0);
            tableLayoutPanel1.SetRow(chartControls[0], 0);

            tableLayoutPanel1.SetColumn(chartControls[1], 0);
            tableLayoutPanel1.SetRow(chartControls[1], 1);
        }

        public void SetupSeries()
        {
            if (Config.Items.Length > 1)
            {
                SetupSeries(0);
                SetupSeries(1);
            }
        }

        /// <summary>
        /// Sets up the scrollbar styles.
        /// </summary>
        private void SetupScrollBarStyles(ChartControl chart)
        {
            ScrollBarVisualStyle moStyle =
                chart.DefaultVisualStyles.HScrollBarVisualStyles.MouseOver;

            moStyle.ArrowBackground = new Background(Color.AliceBlue);
            moStyle.ThumbBackground = new Background(Color.AliceBlue);

            ScrollBarVisualStyle smoStyle =
                chart.DefaultVisualStyles.HScrollBarVisualStyles.SelectedMouseOver;

            smoStyle.ArrowBackground = new Background(Color.White);
            smoStyle.ThumbBackground = new Background(Color.White);

            moStyle = chart.DefaultVisualStyles.VScrollBarVisualStyles.MouseOver;

            moStyle.ArrowBackground = new Background(Color.AliceBlue);
            moStyle.ThumbBackground = new Background(Color.AliceBlue);

            smoStyle = chart.DefaultVisualStyles.VScrollBarVisualStyles.SelectedMouseOver;

            smoStyle.ArrowBackground = new Background(Color.White);
            smoStyle.ThumbBackground = new Background(Color.White);
        }

        /// <summary>
        /// Adds a new chart to the ChartControl
        /// </summary>
        private ChartXy AddChart(ChartControl chart)
        {
            // Create a new ChartXy.

            ChartXy chartXy = new ChartXy
            {
                Name = "RealTime",
                MinContentSize = new Size(300, 300),

                // We want to display the plot a a straight line, with points unsorted.

                ChartLineDisplayMode =
                ChartLineDisplayMode.DisplayLine | ChartLineDisplayMode.DisplayUnsorted
            };

            // Setup various styles for the chart...
            var title = new ChartTitle();
            title.ChartTitleVisualStyle.Alignment = Alignment.MiddleCenter;
            chartXy.Titles.Add(title);

            SetupChartStyle(chartXy);
            SetupContainerStyle(chartXy);
            SetupChartAxes(chartXy);
            SetupChartLegend(chartXy);

            // Add associated series.

            //SetupSeries();

            // And finally, add the chart to the ChartContainers
            // collection of chart elements.

            chart.ChartPanel.ChartContainers.Add(chartXy);

            return chartXy;
        }

        /// <summary>
        /// Sets up the chart axes.
        /// </summary>
        /// <param name="chartXy"></param>
        private void SetupChartAxes(ChartXy chartXy)
        {
            // X Axis

            ChartAxis axis = chartXy.AxisX;
            axis.MinorTickmarks.TickmarkCount = 5;
            axis.AxisMargins = 0;
            //axis.GridSpacing = 50;
            axis.GridSpacing = maxPointCount / 20;

            axis.MajorGridLines.GridLinesVisualStyle.LineColor = Color.Gainsboro;
            axis.MinorGridLines.GridLinesVisualStyle.LineColor = Color.WhiteSmoke;

            // Y Axis

            axis = chartXy.AxisY;

            axis.AxisAlignment = AxisAlignment.Far;
            axis.MinorTickmarks.TickmarkCount = 5;
            //axis.GridSpacing = 50

            axis.MajorGridLines.GridLinesVisualStyle.LineColor = Color.Gainsboro;
            axis.MinorGridLines.GridLinesVisualStyle.LineColor = Color.WhiteSmoke;

            // Display the alternate background.

            axis.ChartAxisVisualStyle.AlternateBackground = new Background(Color.FromArgb(250, 250, 250));

            axis.UseAlternateBackground = true;
        }

        /// <summary>
        /// Sets up the chart style.
        /// </summary>
        /// <param name="chartXy"></param>
        private void SetupChartStyle(ChartXy chartXy)
        {
            ChartXyVisualStyle xystyle = chartXy.ChartVisualStyle;

            xystyle.Background = new Background(Color.White);
            xystyle.BorderThickness = new Thickness(1);
            xystyle.BorderColor = new BorderColor(Color.Black);

            xystyle.Padding = new DevComponents.DotNetBar.Charts.Style.Padding(4);
        }

        /// <summary>
        /// Sets up the chart's container style.
        /// </summary>
        /// <param name="chartXy"></param>
        private void SetupContainerStyle(ChartXy chartXy)
        {
            ContainerVisualStyle dstyle = chartXy.ContainerVisualStyles.Default;

            dstyle.Background = new Background(Color.White);
            dstyle.BorderColor = new BorderColor(Color.DimGray);
            dstyle.BorderThickness = new Thickness(1);

            dstyle.DropShadow.Enabled = Tbool.True;
            dstyle.Padding = new DevComponents.DotNetBar.Charts.Style.Padding(6);
        }

        /// <summary>
        /// Sets up the Legend style.
        /// </summary>
        /// <param name="chartXy"></param>
        private void SetupChartLegend(ChartXy chartXy)
        {
            ChartLegend legend = chartXy.Legend;

            legend.Placement = Placement.Outside;
            legend.Alignment = Alignment.TopCenter;
            legend.AlignVerticalItems = true;
            legend.Direction = Direction.LeftToRight;

            ChartLegendVisualStyle lstyle = legend.ChartLegendVisualStyles.Default;

            lstyle.BorderThickness = new Thickness(1);
            lstyle.BorderColor = new BorderColor(Color.Crimson);

            lstyle.Margin = new DevComponents.DotNetBar.Charts.Style.Padding(8);
            lstyle.Padding = new DevComponents.DotNetBar.Charts.Style.Padding(4);

            lstyle.Background = new Background(Color.FromArgb(200, Color.White));
        }

        /// <summary>
        /// Adds a series to the given chart.
        /// </summary>
        private void SetupSeries(int index)
        {
            if (index >= chartXyControls.Length || index >= Config.Items.Length)
            {
                return;
            }

            ChartXy chartXy = chartXyControls[index];
            ChartConfig config = Config.Items[index];
            if (chartXy == null && config == null)
            {
                return;
            }

            var temp = chartXy.ChartSeries.ToList();
            chartXy.ChartSeries.Clear();

            var collection = chartXyUpdateCollections[index];
            collection.Clear();

            foreach (var configItem in config.Items)
            {
                var item = temp.Find(x => Convert.ToInt32(x.Tag) == configItem.Index);
                if (item == null)
                {
                    item = new ChartSeries(configItem.Title, SeriesType.Line)
                    {
                        Tag = configItem.Index
                    };
                }
                item.Name = configItem.Title;
                chartXy.ChartSeries.Add(item);

                collection.Add(new ControlDataUpdater<Tuple<int, ChartSeries>>()
                {
                    Action = ChartUpdateAction,
                    Parameter = new Tuple<int, ChartSeries>(config.DataIndex, item),
                    Start = configItem.Index
                });
            }
        }

        private void ChartUpdateAction(double time, double value, Tuple<int, ChartSeries> arg2)
        {
            var cs = arg2.Item2;
            cs.SeriesPoints.Add(new SeriesPoint(time, value));

            if (cs.SeriesPoints.Count > maxPointCount)
            {
                cs.SeriesPoints.RemoveRange(0,
                    cs.SeriesPoints.Count - maxPointCount);
            }
        }

        #endregion

    }
}
